//
// Created by tacom on 2024/9/24.
//

#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include "string.h"
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/uart.h"

#include "dev_lowlevel.h"

/**  protocol config    **/
// uart
#define UART_ID uart0
#define UART_RATE 115200
#define UART_TX_PIN 0
#define UART_RX_PIN 1
static char uart_buffer[256];

// led status
static bool LED_STATUS = true;

// print to uart
void print_to_uart(const char *format, ...){
    va_list args;
    va_start(args, format);

    memset(uart_buffer, 0, 256);
    int len = vsnprintf(uart_buffer, 256, format, args);
    va_end(args);

    //uart_puts(UART_ID, uart_buffer);
    uart_write_blocking(UART_ID, (uint8_t *)uart_buffer, len);
}

void blink_led(){
    gpio_put(PICO_DEFAULT_LED_PIN, LED_STATUS);
    LED_STATUS = !LED_STATUS;
}

void printbuf(uint8_t buf[], size_t len) {
    size_t i;
    for (i = 0; i < len; ++i) {
        if (i % 16 == 15)
            print_to_uart("%02x\r\n", buf[i]);
        else
            print_to_uart("%02x ", buf[i]);
    }

    // append trailing newline if there isn't one
    if (i % 16) {
        print_to_uart("\r\n");
    }
}

// re-implement usb data_in, data_out
void ep1_out_handler(uint8_t *buf, uint16_t len) {
    printf("Main: RX %d bytes from host\n", len);

    // Send data back to host
    struct usb_endpoint_configuration *ep = usb_get_endpoint_configuration(EP2_IN_ADDR);
    usb_start_transfer(ep, buf, len);

    printf("Recv buf is: %s\n", (unsigned char *)buf);
    blink_led();
}

void ep2_in_handler(uint8_t *buf, uint16_t len) {
    // 此buffer可能来自: static uint8_t ep0_buf[64];
    printf("Main: Sent %d bytes to host, buf is: %s\n", len, (unsigned char *)buf);
    // Get ready to rx again from host
    usb_start_transfer(usb_get_endpoint_configuration(EP1_OUT_ADDR), NULL, 64);
}


int main(void) {
    // enable and init usb
    stdio_init_all();
    usb_device_init();

    // enable uart
    uart_init(UART_ID, UART_RATE);
    gpio_set_function(UART_TX_PIN, UART_FUNCSEL_NUM(UART_ID, UART_TX_PIN));
    gpio_set_function(UART_RX_PIN, UART_FUNCSEL_NUM(UART_ID, UART_RX_PIN));
    print_to_uart("Init uart done\r\n");

    // enable led
    gpio_init(PICO_DEFAULT_LED_PIN);
    gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
    print_to_uart("Init led done\r\n");

    // Wait until configured
    print_to_uart("Main: Start to Wait Config\r\n");
    while (!configured) {
        tight_loop_contents();
    }

    print_to_uart("Main: Config Done, Start to transfer data first\r\n");
    // Get ready to rx from host
    usb_start_transfer(usb_get_endpoint_configuration(EP1_OUT_ADDR), NULL, 64);

    print_to_uart("Main: Start to loop event\r\n");
    // Everything is interrupt driven so just loop here
    while (1) {
        tight_loop_contents();
    }
}